﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using GosWeb.Biz;


namespace GosWeb.Models.Db
{
    public class Biont
    {
        private GosDBContext db = GosDBContext.GetInstance();

        public Biont()
        {
            Sex = -1;
            //NestNumber = -1;
        }

        [Key]
        [StringLength(20, ErrorMessage = "长度最长为20")]
        [Display(Name = "耳缺号")]
        [Required(ErrorMessage = "必填", AllowEmptyStrings = false)]
        public string BiontID { get; set; }

        /// <summary>
        /// 0:雄(公)，1：雌(母)
        /// </summary>
        [Display(Name = "性别")]
        public short Sex { get; set; }

        [Display(Name = "胎次")]
        //[Required(ErrorMessage = "必填", AllowEmptyStrings = false)]
        public short? NestNumber { get; set; }

        [Display(Name = "生日")]
        [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
        [DataType(DataType.Date)]
        public DateTime? Birthday { get; set; }

        [Display(Name = "地址")]
        public Location Address { get; set; }

        [Display(Name = "左乳")]
        public short? LeftTitNumber { get; set; }

        [Display(Name = "右乳")]
        public short? RightTitNumber { get; set; }

        /// <summary>
        /// 出生重量
        /// </summary>
        [Display(Name = "出生重")]
        public float? Weight { get; set; }   
        
        /// <summary>
        /// 会打印在客户看的单据上
        /// </summary>
        [Display(Name = "备注")]
        [StringLength(5000)]
        [DataType(DataType.MultilineText)]
        public string PubInfo { get; set; }

        /// <summary>
        /// 不会打印在客户看的单据上
        /// </summary>
        [Display(Name = "内部备注")]
        [StringLength(5000)]
        [DataType(DataType.MultilineText)]
        public string PrivInfo { get; set; }


        [Display(Name = "创建日期")]
        public DateTime? CreateDate { get; set; }       

        /// <summary>
        /// 包含：存栏, 死亡，淘汰, 出售, 留种, 胎死,外部 等几种状态。
        /// </summary>
        [Display(Name = "来源去向")]
        public short FromTo { get; set; }

        //[Display(Name = "原种")]
        //public bool Protospecies { get; set; }

        [Display(Name = "品种")]
        [NotMapped]
        public string GeneRatioLongStr
        {
            get
            {
                string str = string.Empty;
                ICollection<GeneRatio> grs = GetGeneRatios();
                if (grs != null)
                {
                    foreach (var item in grs)
                    {
                        string r = (item.Ratio).ToString("####.##");
                        str += string.Format("{0}({1}{2}) ", GeneBiz.GetInstance().GetGeneName(item.GeneCode), item.GeneCode, r); 
                    }
                }
                return str.Trim();
            }
        }

        [Display(Name = "品种")]
        public string GenesMidStr()
        {
            string str = string.Empty;
            ICollection<GeneRatio> grs = GetGeneRatios();
            if (grs != null)
            {
                foreach (var item in grs)
                {
                    //string r = (item.Ratio).ToString("####.##");
                    str += string.Format("{0}({1}) ", GeneBiz.GetInstance().GetGeneName(item.GeneCode), item.GeneCode);
                }
            }
            return str.Trim();

        }

        [Display(Name = "品种")]
        [NotMapped]
        public string GenesShortStr
        {
            get
            {
                string str = string.Empty;
                ICollection<GeneRatio> grs = GetGeneRatios();
                if (grs != null)
                {
                    foreach (var item in grs)
                    {
                        //string r = (item.Ratio).ToString("####.##");
                        string t = GeneBiz.GetInstance().GetGeneName(item.GeneCode);
                        if (string.IsNullOrWhiteSpace(t))
                        {
                           str+= '?';
                        }
                        else
                        {
                            str += t[0];
                        } 
                    }
                }
                return str.Trim();
            }
        }

        public string GetGenesEngStr()
        {
                string str = string.Empty;
                ICollection<GeneRatio> grs = GetGeneRatios();
                if (grs != null)
                {
                    foreach (var item in grs)
                    {
                        //string r = (item.Ratio).ToString("####.##");
                        string t = item.GeneCode;
                        if (string.IsNullOrWhiteSpace(t))
                        {
                            str += '?';
                        }
                        else
                        {
                            str += t;
                        }
                    }
                }
                return str;
        }

        [NotMapped]
        public string FromToStr
        {
            get
            {
                try
                {
                    return FromToValue.FromToes[FromTo].Name;
                }
                catch
                {
                    return "出错:超出范围";
                }

            }
        }

        [Display(Name = "雌雄(公母)")]
        [NotMapped]
        public string SexStr
        {
            get
            {
                string sex = "未知";
                if (Sex == 0)
                {
                    sex = "公";
                }
                if (Sex == 1)
                {
                    sex = "母";
                }
                return sex;
            }
        }


        public string GetParentStr()
        {
                string sex = "?";
                if (Sex == 0)
                {
                    sex = "父";
                }
                if (Sex == 1)
                {
                    sex = "母";
                }
                return sex;
        }


        private GeneRatio existGeneRatio(ICollection<GeneRatio> grs, string geneCode)
        {
            foreach (var item in grs)
            {
                if (item.GeneCode == geneCode)
                    return item;
            }
            return null;
        }

        //public true LoadFathermother()
        //{

        //}

        //public abstract ICollection<GeneRatio> GetGeneRatios();

        public virtual ICollection<GeneRatio> GetGeneRatios()
        {
            //try to get the Gene info, if no then calc it.
            if (string.IsNullOrWhiteSpace(this.FatherID) && string.IsNullOrWhiteSpace(this.MotherID))
            {
                if (db.Entry(this).Collection(u => u.GeneRatios).IsLoaded == false)
                {
                    db.Entry(this).Collection(u => u.GeneRatios).Load();
                }


                if (GeneRatios != null && GeneRatios.Count > 0)
                {
                    return GeneRatios;
                }
            }
            ICollection<GeneRatio> grs = new List<GeneRatio>();
            //grs.Clear();
            //--from father side-----------
            Biont f = GetFather();
            if (f == null)
            {
                //throw new Exception(string.Format("Not found {0}'s Father:{1}\n", BiontID, FatherID));
            }
            else
            {
                foreach (var item in f.GetGeneRatios())
                {
                    GeneRatio gr = existGeneRatio(grs, item.GeneCode);
                    if (gr == null)
                    {
                        var t = new GeneRatio();
                        t.AnID = BiontID;
                        t.GeneCode = item.GeneCode;
                        t.Ratio = item.Ratio / 2;
                        if (t.Ratio > 0)
                        {
                            grs.Add(t);
                        }
                    }
                    else
                    {
                        gr.Ratio += item.Ratio / 2;
                    }

                }
            }

            //--from mother side------------
            Biont m = GetMother();
            if (m == null)
            {
                //throw new Exception(string.Format("Not found {0}'s Mother:{1}\n", BiontID, MotherID));
            }
            else
            {
                foreach (var item in m.GetGeneRatios())
                {
                    GeneRatio gr = existGeneRatio(grs, item.GeneCode); //GetAGeneRatio(item.GeneCode); 相互依赖

                    if (gr == null)
                    {
                        var t = new GeneRatio();
                        t.AnID = BiontID;
                        t.GeneCode = item.GeneCode;
                        t.Ratio = item.Ratio / 2;
                        if (t.Ratio > 0)
                        {
                            grs.Add(t);
                        }
                    }
                    else
                    {
                        gr.Ratio += item.Ratio / 2;
                    }
                }
            }
            return grs;
        }

        /// <summary>
        /// percent
        /// </summary>
        //[NotMapped]
        public decimal SumGeneRatio()
        {
            //get
            {
                decimal sum = 0;
                foreach (var item in GetGeneRatios())
                {
                    sum += item.Ratio;
                }
                return sum;
            }
        }

        /// <summary>
        /// 验证血统是否为100%
        /// </summary>
        /// <returns></returns>
        public bool IsGeneRatioCompletion()
        {
            decimal diff = SumGeneRatio() - 100;
            if (diff < 0)
            {
                diff = -diff;
            }

            if (diff < 0.1m)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        //[NotMapped]
        public decimal GeneAmount()
        {
            //get
            {
                decimal am = 0;
                foreach (var item in GetGeneRatios())
                {
                    am += item.Ratio;
                };
                return am;
            }
        }

        public virtual GeneRatio GetAGeneRatio(string geneCode)
        {
            foreach (var item in GetGeneRatios())
            {
                if (item.GeneCode == geneCode)
                    return item;
            }
            return null;
        }

        [ForeignKey("AnID")]
        public ICollection<GeneRatio> GeneRatios { get; set; }

        [ForeignKey("AnID")]
        public ICollection<MedicalRecord> MedicalRecords { get; set; }

        //[ForeignKey("AnID")]
        //public FatherMother Fathermother { get; set; }

        [Display(Name = "父亲")]
        //[Required(ErrorMessage = "必填", AllowEmptyStrings = false)]
        public string FatherID { get; set; }

        [Display(Name = "母亲")]
        //[Required(ErrorMessage = "必填", AllowEmptyStrings = false)]
        public string MotherID { get; set; }

        public bool NoFatherMother()
        {
            if (string.IsNullOrWhiteSpace(FatherID) && string.IsNullOrWhiteSpace(MotherID))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public Biont GetFather()
        {
            Biont a = db.Bionts.Find(FatherID);
            return a;
        }

        public bool ValidFatherGender()
        {
            Biont a = GetFather();
            if (a.Sex == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public Biont GetMother()
        {
            Biont a = db.Bionts.Find(this.MotherID);
            //if (a == null)
            //{
            //    a = db.BiontProtos.Find(MotherID);
            //}
            return a;
        }

        public bool ValidMotherGender()
        {
            Biont a = GetMother();
            if (a.Sex == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public IEnumerable<Biont> GetSonDaughters()
        {
            var bionts = from m in db.Bionts where (m.FatherID == this.BiontID || m.MotherID == this.BiontID) orderby m.Birthday descending select m;
            return bionts;
        }

        public IEnumerable<Biont> GetOffspring()
        {
            List<Biont> offspring = new List<Biont>();
            var sd = GetSonDaughters();
            foreach (var item in sd)
            {
                offspring.Add(item);
                var os = item.GetOffspring();
                offspring.AddRange(os);
            }

            return offspring;
        }

        /// <summary>
        /// check whether is it's offspring
        /// </summary>
        /// <param name="biontId"></param>
        /// <returns></returns>
        private bool IsOffspring(string biontId)
        {
            if (string.IsNullOrEmpty(biontId))
            {
                return false;
            }
            else
            {
                biontId = biontId.Trim();
            }
            bool b = false;
            var os = GetOffspring();
            foreach (var item in os)
            {
                if (item.BiontID == biontId)
                {
                    b = true;
                    break;
                }
            }
            return b;
        }

        public bool IsOffspringOrSelf(string biontid)
        {
            if (string.IsNullOrEmpty(biontid))
            {
                return false;
            }
            else
            {
                biontid = biontid.Trim();
            }
            if (biontid == BiontID)
            {
                return true;
            }
            bool b = false;
            b = IsOffspring(biontid);
            return b;
        }

        public string GetLongID()
        {
            string s = string.Format("{0}-{1}-{2}", this.GetGenesEngStr(), this.Address.Site, this.BiontID);
            return s;
        }

        public object Clone()
        {
            Biont bn = new Biont();
            bn.BiontID = this.BiontID;
            bn.Address = this.Address.Clone() as Location;
            bn.LeftTitNumber = this.LeftTitNumber;
            bn.RightTitNumber = this.RightTitNumber;
            bn.Weight = this.Weight;
            bn.Birthday = this.Birthday;
            bn.PubInfo = this.PubInfo;
            bn.PrivInfo = this.PrivInfo;
            bn.FatherID = this.FatherID;
            bn.FromTo = this.FromTo;
            bn.MotherID = this.MotherID;
            bn.NestNumber = this.NestNumber;
            bn.Sex = this.Sex;

            return bn;
        }
    }

    public enum FromToType
    {
        Undefined = 0,//未定义
        WeedOut,//淘汰
        Died,//死亡
        Saled, //出售
        ForSeed,//留种
        FetalDeath,//胎死
        OutSide//外部的,比如从别的地方借用的种
    }

    public class FromToValue
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public static List<FromToValue> FromToes = new List<FromToValue> { 
            new FromToValue { Id = 0, Name = "未定"},
            new FromToValue { Id = 1,Name = "淘汰"},
            new FromToValue { Id = 2, Name = "死亡"},
            new FromToValue { Id = 3,Name = "出售"},
            new FromToValue { Id = 4, Name = "留种"},
            new FromToValue { Id = 5,Name = "胎死"},
            new FromToValue { Id = 6,Name = "外部的"},
        };
    }

    public enum Gender
    {
        Unknow, Male, Female
    }

    public class GenderKeyValue
    {
        public int GenderId { get; set; }
        public string Name { get; set; }
        public static IEnumerable<GenderKeyValue> Genders = new List<GenderKeyValue> { 
            new GenderKeyValue { GenderId = -1, Name = "请选择"},
            new GenderKeyValue { GenderId = 0, Name = "公"},
            new GenderKeyValue { GenderId = 1,Name = "母"}
};
    }


}
